﻿using System;
using System.IO;
using UnityEditor;
using UnityEditor.Build.Profile;
using UnityEditor.Build.Reporting;
using UnityEngine;

namespace UPA
{
    [Serializable]
    public class BuildPlayerActionArgument : ProcessActionArgument
    {
        [SerializeField]
        private string appVersion;
        [SerializeField]
        private int codeVersion;
        [SerializeField]
        private string exportRootPath;
        [SerializeField]
        private BuildProfile profile;

        public string AppVersion => appVersion;
        public int CodeVersion => codeVersion;
        public string ExportRootPath => exportRootPath;
        public BuildProfile Profile => profile;
    }
    [ProcessActionTemplateName("打包")]
    [ProcessActionAllowMultiple]
    public class BuildPlayerAction:ProcessAction
    {
        public override Type RequiredArgument => typeof(BuildPlayerActionArgument);

        public override string Name
        {
            get
            {
                var argument = GetArgument<BuildPlayerActionArgument>();
                if (!argument.Profile)
                {
                    return "打包:未设置";
                }

                return $"打包:{argument.Profile.name}";
            }
        }

        public override ProcessActionResult Execute()
        {
            var argument = GetArgument<BuildPlayerActionArgument>();
            if (!argument.Profile)
            {
                return new ProcessActionResult(false, "未设置打包配置");
            }

            if (string.IsNullOrWhiteSpace(argument.ExportRootPath))
            {
                return new ProcessActionResult(false, "未设置包体存放根路径");
            }

            SetVersion();
            var packageName = GetPackageName();
            var options = new BuildPlayerWithProfileOptions
            {
                buildProfile = argument.Profile,
                locationPathName = Path.Combine(argument.ExportRootPath, packageName).Replace('\\', '/')
            };
            Debug.Log(options.locationPathName);
            
            var result = BuildPipeline.BuildPlayer(options);
            if (result.summary.result == BuildResult.Succeeded)
            {
                Debug.Log($"包体导出路径:{result.summary.outputPath}");
                return new ProcessActionResult(true);
            }
            Debug.Log($"包体导出路径:{result.summary.outputPath}");
            return new ProcessActionResult(false, "打包失败!");
        }

        protected virtual string GetPackageName()
        {
            var argument = GetArgument<BuildPlayerActionArgument>();
            var serializedObject = new SerializedObject(argument.Profile);
            var target = (BuildTarget)serializedObject.FindProperty("m_BuildTarget").boxedValue;
            var productName = GetProductName(serializedObject);
            var extensions = GetExtensions(serializedObject,target,IsExportProject(serializedObject,target),productName);
            return $"{productName}_V{argument.AppVersion}_{argument.CodeVersion}_{DateTime.Now:yyyy_Md_HHMMss}{extensions}";
        }

        protected string GetExtensions(SerializedObject serializedObject,BuildTarget target,bool exportProject,string productName)
        {
            if (exportProject)
            {
                if (target == BuildTarget.StandaloneWindows64 || target == BuildTarget.StandaloneWindows)
                {
                    return $"/{productName}.exe";
                }
                return "/";
            }

            switch (target)
            {
                case BuildTarget.StandaloneWindows: 
                case BuildTarget.StandaloneWindows64:
                    return $"/{productName}.exe";
                case BuildTarget.StandaloneOSX:
                    return ".app";
                case BuildTarget.StandaloneLinux64:
                    return $"/{productName}.x86_64";
                case BuildTarget.Android:
                    return IsAndroidAAB(serializedObject) ? ".aab" : ".apk";
                default:
                    return "/";
            }
        }

        protected string GetProductName(SerializedObject serializedObject)
        {
            var settingsArray = serializedObject.FindProperty("m_PlayerSettingsYaml").FindPropertyRelative("m_Settings");
            for (int i = 0; i < settingsArray.arraySize; i++)
            {
                var property = settingsArray.GetArrayElementAtIndex(i).FindPropertyRelative("line");
                if (property.stringValue.StartsWith("|   productName:"))
                {
                    var kv = property.stringValue.Split(":");
                    if (kv.Length > 1)
                    {
                        return kv[1].Trim();
                    }

                    return string.Empty;
                }
            }
            return PlayerSettings.productName;
        }

        protected bool IsAndroidAAB(SerializedObject serializedObject)
        {
            return serializedObject.FindProperty("m_PlatformBuildProfile").FindPropertyRelative("m_BuildAppBundle").boolValue;
        }

        protected bool IsExportProject(SerializedObject serializedObject,BuildTarget target)
        {
            switch (target)
            {
                case BuildTarget.Android:
                    return serializedObject.FindProperty("m_PlatformBuildProfile").FindPropertyRelative("m_ExportAsGoogleAndroidProject").boolValue;
                case BuildTarget.StandaloneOSX:
                    return serializedObject.FindProperty("m_PlatformBuildProfile").FindPropertyRelative("m_CreateXcodeProject").boolValue;
                case BuildTarget.StandaloneWindows: 
                case BuildTarget.StandaloneWindows64:
                    return serializedObject.FindProperty("m_PlatformBuildProfile").FindPropertyRelative("m_CreateSolution").boolValue;
            }
            return false;
        }

        private void SetVersion()
        {
            var argument = GetArgument<BuildPlayerActionArgument>();
            var serializedObject = new SerializedObject(argument.Profile);
            var settingsArray = serializedObject.FindProperty("m_PlayerSettingsYaml").FindPropertyRelative("m_Settings");
            if (settingsArray.arraySize > 0)
            {
                for (int i = 0; i < settingsArray.arraySize; i++)
                {
                    var property = settingsArray.GetArrayElementAtIndex(i).FindPropertyRelative("line");
                    if (property.stringValue.StartsWith("|   bundleVersion:"))
                    {
                        property.stringValue = $"|   bundleVersion: {argument.AppVersion}";
                    }
                    else if (property.stringValue.StartsWith("|   AndroidBundleVersionCode:"))
                    {
                        property.stringValue = $"|   AndroidBundleVersionCode: {argument.CodeVersion}";
                    }
                    else if (property.stringValue.StartsWith("|   buildNumber:"))
                    {
                        property.stringValue = $"|   buildNumber: {argument.CodeVersion}";
                    }
                }
                serializedObject.ApplyModifiedProperties();
            }
            
            var target = (BuildTarget)serializedObject.FindProperty("m_BuildTarget").boxedValue;
            PlayerSettings.bundleVersion = argument.AppVersion;
            if (target == BuildTarget.iOS)
            {
                PlayerSettings.iOS.buildNumber = argument.CodeVersion.ToString();
            }
            else if (target == BuildTarget.Android)
            {
                PlayerSettings.Android.bundleVersionCode = argument.CodeVersion;
            }
        }
    }
}